import { _decorator, Component, Node, Vec3, BoxCollider2D, Contact2DType, IPhysics2DContact, Collider2D, tween } from 'cc';
import { DataManager, ItemConfig } from '../Core/DataManager';
import { GameManager } from '../GameManager';
import { EventManager, GameEventType } from '../Core/EventManager';
import { ObjectPool } from '../Core/ObjectPool';

const { ccclass, property } = _decorator;

// Item movement states
enum ItemMoveState {
    DROP,
    IDLE,
    ATTRACT
}

@ccclass('ItemController')
export class ItemController extends Component {
    @property
    private itemId: string = "";
    
    @property
    private value: number = 1;
    
    @property
    private moveSpeed: number = 300;
    
    @property
    private attractDistance: number = 3;
    
    @property
    private initialDropForce: number = 200;
    
    @property
    private lifeTime: number = 20;
    
    private _config: ItemConfig = null;
    private _moveState: ItemMoveState = ItemMoveState.DROP;
    private _dropDirection: Vec3 = new Vec3();
    private _dropSpeed: number = 0;
    private _dropTime: number = 0.5;
    private _currentTime: number = 0;
    private _lifeTimer: number = 0;
    private _poolKey: string = "";
    
    start() {
        // Load configuration
        this._config = DataManager.instance.getItemConfig(this.itemId);
        
        // Apply configuration if available
        if (this._config) {
            this.value = this._config.value;
        }
        
        // Set up collision detection
        this.setupCollision();
        
        // Generate random drop direction
        const angle = Math.random() * Math.PI * 2;
        this._dropDirection.x = Math.cos(angle);
        this._dropDirection.y = Math.sin(angle);
        this._dropDirection.z = 0;
        
        // Set initial drop speed
        this._dropSpeed = this.initialDropForce;
        
        // Set pool key for recycling
        this._poolKey = `Item_${this.itemId}`;
    }
    
    update(deltaTime: number) {
        // Update life timer
        this._lifeTimer += deltaTime;
        if (this._lifeTimer >= this.lifeTime) {
            this.recycleSelf();
            return;
        }
        
        // Make item blink if about to expire
        if (this._lifeTimer > this.lifeTime - 3) {
            const blinkRate = (this._lifeTimer % 0.5) < 0.25;
            this.node.active = blinkRate;
        }
        
        // Update based on current state
        switch (this._moveState) {
            case ItemMoveState.DROP:
                this.updateDropMovement(deltaTime);
                break;
                
            case ItemMoveState.IDLE:
                this.updateIdleState(deltaTime);
                break;
                
            case ItemMoveState.ATTRACT:
                this.updateAttractMovement(deltaTime);
                break;
        }
    }
    
    private setupCollision(): void {
        const collider = this.getComponent(BoxCollider2D);
        if (collider) {
            collider.on(Contact2DType.BEGIN_CONTACT, this.onCollisionEnter, this);
        }
    }
    
    private updateDropMovement(deltaTime: number): void {
        // Track drop time
        this._currentTime += deltaTime;
        
        // Gradually slow down
        this._dropSpeed = Math.max(0, this.initialDropForce * (1 - this._currentTime / this._dropTime));
        
        // Calculate movement
        const movement = this._dropDirection.clone().multiplyScalar(this._dropSpeed * deltaTime);
        
        // Update position
        this.node.position = this.node.position.add(movement);
        
        // Transition to idle state when drop is complete
        if (this._currentTime >= this._dropTime) {
            this._moveState = ItemMoveState.IDLE;
        }
    }
    
    private updateIdleState(deltaTime: number): void {
        // Find player for attraction check
        const player = GameManager.instance.getPlayer();
        if (!player) return;
        
        // Check if player is in attraction range
        const distance = Vec3.distance(this.node.position, player.position);
        if (distance <= this.attractDistance) {
            this._moveState = ItemMoveState.ATTRACT;
        }
        
        // Small bouncing animation while idle
        // This would normally be handled by a tween or animation
    }
    
    private updateAttractMovement(deltaTime: number): void {
        // Find player
        const player = GameManager.instance.getPlayer();
        if (!player) {
            this._moveState = ItemMoveState.IDLE;
            return;
        }
        
        // Move towards player
        const direction = new Vec3();
        Vec3.subtract(direction, player.position, this.node.position);
        direction.normalize();
        
        // Calculate movement with faster speed when attracting
        const movement = direction.multiplyScalar(this.moveSpeed * 2 * deltaTime);
        
        // Update position
        this.node.position = this.node.position.add(movement);
        
        // Check if reached player
        const distance = Vec3.distance(this.node.position, player.position);
        if (distance < 0.5) {
            this.pickup();
        }
    }
    
    private onCollisionEnter(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact): void {
        // Check if collided with player
        if (otherCollider.node === GameManager.instance.getPlayer()) {
            this.pickup();
        }
    }
    
    private pickup(): void {
        // Apply item effect based on type
        if (this._config) {
            switch (this._config.type) {
                case 'exp':
                    GameManager.instance.addExperience(this.value);
                    EventManager.instance.emit(GameEventType.EXP_GAIN, this.value);
                    break;
                    
                case 'health':
                    // Emit health pickup event for player to handle
                    EventManager.instance.emit(GameEventType.ITEM_PICKUP, {
                        type: 'health',
                        value: this.value
                    });
                    break;
                    
                case 'currency':
                    // Add currency to player stats (would be handled by a dedicated manager in a full game)
                    EventManager.instance.emit(GameEventType.ITEM_PICKUP, {
                        type: 'currency',
                        value: this.value
                    });
                    break;
                    
                default:
                    // Generic item pickup
                    EventManager.instance.emit(GameEventType.ITEM_PICKUP, {
                        type: this._config.type,
                        value: this.value
                    });
                    break;
            }
        }
        
        // Play pickup effect if needed
        this.playPickupEffect();
        
        // Recycle the item
        this.recycleSelf();
    }
    
    private playPickupEffect(): void {
        // Play pickup effect (would typically create a floating text or particle effect)
        // For now, we'll just use a simple scale effect before destroying
        tween(this.node)
            .to(0.1, { scale: new Vec3(1.5, 1.5, 1.5) })
            .to(0.1, { scale: new Vec3(0, 0, 0) })
            .call(() => {
                // This callback is intentionally empty as recycleSelf is called elsewhere
            })
            .start();
    }
    
    private recycleSelf(): void {
        // Return to object pool or destroy if not from pool
        if (this._poolKey && ObjectPool.instance) {
            ObjectPool.instance.returnObject(this._poolKey, this.node);
        } else {
            this.node.destroy();
        }
    }
    
    // Public method to initialize the item
    public initialize(itemId: string, position?: Vec3): void {
        this.itemId = itemId;
        
        if (position) {
            this.node.position = position;
        }
        
        // Reset state
        this._moveState = ItemMoveState.DROP;
        this._currentTime = 0;
        this._lifeTimer = 0;
        
        // Reload configuration
        this._config = DataManager.instance.getItemConfig(this.itemId);
        
        // Apply configuration if available
        if (this._config) {
            this.value = this._config.value;
        }
        
        // Generate new random drop direction
        const angle = Math.random() * Math.PI * 2;
        this._dropDirection.x = Math.cos(angle);
        this._dropDirection.y = Math.sin(angle);
        this._dropDirection.z = 0;
        
        // Reset visibility and scale
        this.node.active = true;
        this.node.scale = new Vec3(1, 1, 1);
    }
    
    onDestroy() {
        // Clean up event listeners
        const collider = this.getComponent(BoxCollider2D);
        if (collider) {
            collider.off(Contact2DType.BEGIN_CONTACT, this.onCollisionEnter, this);
        }
    }
} 